#pragma once
/*管理匹配队列，一个线程管理一个队列*/
#include "MatchQueue.hpp"
#include "Common.hpp"
#include "GameRoomManager.hpp"
#include "OnlineManager.hpp"

/*段位划分*/
#define BRONZE 1000
#define SILVER 2000
#define GOLD 3000
class MatchManager
{
private:
    /*青铜、白银、黄金段位匹配队列*/
    MatchQueue<LL> _match_queue_bronze;
    MatchQueue<LL> _match_queue_silver;
    MatchQueue<LL> _match_queue_gold;
    /*一个线程管理一个匹配队列*/
    std::thread _tid_bronze;
    std::thread _tid_silver;
    std::thread _tid_gold;
    /*房间管理类分配房间*/
    GameRoomManager *_room_manager;
    /*拿到uid去数据库查找用户积分信息，来选择不同的匹配队列*/
    db::UserInfo *_user_table;
    /*在线用户管理器*/
    OnlineManager *_online_manager;
private:
    // 线程入口绑定
    void MatchEntry(MatchQueue<LL> &match_queue)
    {
        // 匹配队列永不退出
        while (true)
        {
            // 先判断自己管理的匹配队列中玩家是否 >= 2
            while (match_queue.Size() < 2)
            {
                // 阻塞，等待生产者
                match_queue.Wait();
            }
            // 获取2个玩家
            LL uid1 = 0, uid2 = 0;
            bool ret = match_queue.Pop(uid1);
            if (ret == false)
            {
                continue;
            }
            // 走到这里说明至少存在一个玩家处于匹配状态
            ret = match_queue.Pop(uid2);
            if (ret == false)
            {
                // 队列为空,重新让第一个出队的玩家回去继续匹配，直到新玩家到来
                Add(uid1);
                continue;
            }
            // 走到这里说明存在2个正在匹配的玩家
            // 判断是否在线
            WebSocketServer::connection_ptr conn1 = _online_manager->GetConnByHail(uid1).second;
            if (conn1 == nullptr)
            {
                // 将玩家2重新匹配
                Add(uid2);
                continue;
            }
           WebSocketServer::connection_ptr conn2 = _online_manager->GetConnByHail(uid2).second;
            if (conn2 == nullptr)
            {
                // 将玩家1重新匹配
                Add(uid1);
                continue;
            }
            //分配房间
            Room_ptr room = _room_manager->CreateRoom(uid1,uid2);
            if(room == nullptr)
            {
                //重新匹配
                Add(uid1);
                Add(uid2);
                continue;
            }
            //匹配成功是不是要对双方进行提示啊！！！？发送Json响应
            Json::Value rsp;
            rsp["optype"] = "match_success";
            rsp["result"] = true;
            std::string info;
            util::JsonTool::Serialization(rsp,&info);
            conn1->send(info);
            conn2->send(info);
        }
    }
public:
    /*这里有个坑！！bind参数的时候使用std::ref表示绑定的是引用方式！！*/
    MatchManager(GameRoomManager *room_manager, db::UserInfo *user_table, OnlineManager *online_manager)
        : _tid_bronze(std::bind(&MatchManager::MatchEntry, this, std::ref(_match_queue_bronze))),
          _tid_silver(std::bind(&MatchManager::MatchEntry, this, std::ref(_match_queue_silver))),
          _tid_gold(std::bind(&MatchManager::MatchEntry, this, std::ref(_match_queue_gold))),
          _room_manager(room_manager),
          _user_table(user_table),
          _online_manager(online_manager)
    {
        LOG(DEBUG, "匹配队列管理类创建完毕\n");
    }
    // 增加用户到匹配队列
    bool Add(LL uid)
    {
        Json::Value user;
        // 去数据库查询
        if (!_user_table->FindUser(uid, user))
        {
            LOG(ERROR, "uid:%lu不存在,无法进入匹配队列\n", uid);
            return false;
        }
        int score = user["score"].asInt();
        if (score >= BRONZE && score < SILVER)
        {
            _match_queue_bronze.Push(uid);
        }
        else if (score >= SILVER && score < GOLD)
        {
            _match_queue_silver.Push(uid);
        }
        else
        {
            _match_queue_gold.Push(uid);
        }
        return true;
    }
    // 移除匹配中的用户
    bool Remove(LL uid)
    {
        Json::Value user;
        // 去数据库查询
        if (!_user_table->FindUser(uid, user))
        {
            LOG(ERROR, "uid:%lu不存在,无法从匹配队列中删除\n", uid);
            return false;
        }
        int score = user["score"].asInt();
        if (score >= BRONZE && score < SILVER)
        {
            _match_queue_bronze.Remove(uid);
        }
        else if (score >= SILVER && score < GOLD)
        {
            _match_queue_silver.Remove(uid);
        }
        else
        {
            _match_queue_gold.Remove(uid);
        }
        return true;
    }
    ~MatchManager()
    {
    }
};